package com.superbytecode.cloud.web.result;

import com.superbytecode.cloud.common.result.NonResultWrapper;
import com.superbytecode.cloud.common.result.ResultWrapper;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;

import javax.servlet.ServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * All rights Reserved, Designed By www.super-master.com
 *
 * @ProjectName: beacon-cloud
 * @Package: com.superbytecode.cloud.web.mvc
 * @ClassName: WebMvcProcessAdviceDecorator
 * @Description: []
 * <p> </p>
 * @Author: [Lance Ting]
 * @Date: 2024/10/22 10:42
 * @Version: V1.0
 * @Copyright: 2024 www.super-master.cn Inc. All rights reserved.
 * TODO: 注意,本文件Lance Ting所作,如果转载或使用请标明具体出处!
 **/
@Configuration
public class WebMvcProcessAdviceDecorator implements InitializingBean {
    private final RequestMappingHandlerAdapter mappingHandlerAdapter;

    public WebMvcProcessAdviceDecorator(RequestMappingHandlerAdapter mappingHandlerAdapter) {
        this.mappingHandlerAdapter = mappingHandlerAdapter;
    }

    /**
     * @throws Exception 异常
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        // 获取所有的handler对象
        List<HandlerMethodReturnValueHandler> returnValueHandlers = mappingHandlerAdapter.getReturnValueHandlers();
        assert returnValueHandlers != null;
        List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(returnValueHandlers);
        this.decorateHandlers(handlers);
        //将增强的返回值回写回去
        mappingHandlerAdapter.setReturnValueHandlers(handlers);
    }

    // 使用自定义的返回值控制类
    private void decorateHandlers(List<HandlerMethodReturnValueHandler> valueHandlers) {
        for (HandlerMethodReturnValueHandler valueHandler : valueHandlers) {
            if (!(valueHandler instanceof RequestResponseBodyMethodProcessor)) {
                continue;
            }
            //找到返回值的handler并将起包装成自定义的handler
            ControllerReturnValueHandler decorator = new ControllerReturnValueHandler((RequestResponseBodyMethodProcessor) valueHandler);
            int index = valueHandlers.indexOf(valueHandler);
            valueHandlers.set(index, decorator);
        }
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 自定义返回值的Handler
     **/
    private static class ControllerReturnValueHandler implements HandlerMethodReturnValueHandler {
        //持有一个被装饰者对象
        private final HandlerMethodReturnValueHandler methodReturnValueHandler;

        ControllerReturnValueHandler(RequestResponseBodyMethodProcessor bodyMethodProcessor) {
            this.methodReturnValueHandler = bodyMethodProcessor;
        }

        /**
         * 是否支持 MethodParameter类型
         *
         * @param returnType 返回类型
         * @return 结果
         */
        @SuppressWarnings("all")
        @Override
        public boolean supportsReturnType(MethodParameter returnType) {
            return true;
        }

        /**
         * 对方法返回值进行处理
         * <p>增强被装饰者的功能</p>
         *
         * @param returnValue  返回值
         * @param returnType   返回类型
         * @param mavContainer view
         * @param webRequest   请求对象
         * @throws Exception 抛出异常
         */
        @SuppressWarnings("all")
        @Override
        public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
            // 返回类型不做包装，如文件类型等
            if (Objects.nonNull(returnType.getMethodAnnotation(NonResultWrapper.class))) {
                methodReturnValueHandler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
                return;
            }
            // 返回值为空
            if (Objects.isNull(returnValue)) {
                Optional<String> contentType = Optional.of(webRequest)//
                        .map(nativeWebRequest -> ((ServletWebRequest) webRequest))//
                        .map(ServletRequestAttributes::getResponse)//
                        .map(ServletResponse::getContentType);
                // 文件格式数据
                if (contentType.isPresent() && contentType.get().contains("application/vnd.openxmlformats-officedocument")) {
                    return;
                }
            }
            // 如果已经封装
            if (returnValue instanceof ResultWrapper) {
                methodReturnValueHandler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
                return;
            }
            //正常返回success
            ResultWrapper<Object> success = ResultWrapper.success(returnValue);
            methodReturnValueHandler.handleReturnValue(success, returnType, mavContainer, webRequest);
        }
    }
}